package bll

import (
	"context"
	"fmt"
	"gorm.io/gorm"
	"manager/errors"
	"manager/store/postgres"
	"manager/utils"
	"time"

	"manager/event"
	"manager/model"
	"manager/model/entity"
	"manager/store"
)

type ebikeType struct {
	iEbikeType store.IEbikeType
}

var EbikeType = &ebikeType{}

func (a *ebikeType) init() func() {
	a.iEbikeType = postgres.EbikeType
	return func() {}
}

func (a *ebikeType) onEvent(*event.Data) {}

func (a *ebikeType) Create(ctx context.Context, in *model.EbikeTypeCreateRequest) (id int64, err error) {
	// 车型名称校验
	var count int64
	postgres.GetDB(ctx).Model(&entity.EbikeType{}).Where("name = ?", in.Name).Count(&count)
	if count > 0 {
		return 0, fmt.Errorf("车型名称已存在")
	}

	// 车型编码校验
	postgres.GetDB(ctx).Model(&entity.EbikeType{}).Where("code = ?", in.Code).Count(&count)
	if count > 0 {
		return 0, fmt.Errorf("车型编码已存在")
	}

	c := buildEbikeType(in)
	id, err = a.iEbikeType.Create(c)
	// 重复索引做判断
	if err != nil {
		return
	}

	return
}
func (a *ebikeType) QueryTypeByCode(ctx context.Context, code string) (entity.EbikeType, error) {
	var t entity.EbikeType
	err := postgres.GetDB(ctx).Model(&entity.EbikeType{}).Where("code=?", code).First(&t).Error
	return t, err
}

func (a *ebikeType) Update(ctx context.Context, in *model.EbikeTypeUpdateRequest) error {
	var (
		dict = make(map[string]interface{})
	)
	if in.Name != nil {
		dict["name"] = *in.Name
	}

	if len(in.Color) > 0 {
		dict["color"] = in.Color
	}

	if in.SocketType != nil {
		dict["socket_type"] = *in.SocketType

	}
	if in.Status != nil {
		dict["status"] = *in.Status
	}

	if in.ParentID != nil {
		dict["parent_id"] = in.ParentID
	}

	if in.Price != nil {
		dict["price"] = in.Price
	}

	if in.ImagePath != nil {
		dict["image_path"] = in.ImagePath
	}

	if in.Code != nil {
		dict["code"] = in.Code
	}

	if in.Config != nil {
		dict["config"] = in.Config
		dict["config_update_at"] = time.Now().Unix()
	}

	if in.Image != nil {
		dict["image"] = in.Image
	}

	// 更新前删除缓存
	CacheBikeType.DeleteCache(in.ID)

	// 更新
	err := a.iEbikeType.Update(in.ID, dict)
	if err != nil {
		return err
	}

	// 更新后删除缓存
	CacheBikeType.DeleteCache(in.ID)
	return err
}

func (a *ebikeType) Delete(ctx context.Context, in *model.EbikeTypeDeleteRequest) error {
	// 判断车型是否存在车辆
	rsp, _ := Ebike.List(ctx, &model.EbikeListRequest{
		Index:  1,
		Size:   1,
		TypeID: &in.ID,
	})

	if rsp.Total > 0 {
		return errors.ErrEbikeTypeHasEbike.Error()
	}
	return a.iEbikeType.Delete(in.ID)
}

func (a *ebikeType) List(ctx context.Context, in *model.EbikeTypeListRequest) (*model.EbikesTypeListResponse, error) {
	var (
		err   error
		total int
		out   = &model.EbikesTypeListResponse{}
		list  []*model.EbikeTypeListInfoResponse
	)

	in.Size, in.Index = utils.PageUtil(in.Size, in.Index)

	if total, list, err = a.iEbikeType.List(in); err != nil {
		return nil, err
	}

	out.Total = total
	out.Data = list

	return out, nil
}

// IsExistBikeType 判断车型是否存在
func (a *ebikeType) IsExistBikeType(bikeType int64) bool {
	// 判断车型是否存在
	_, err := a.iEbikeType.Find(bikeType)
	if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		return false
	}

	return true
}

// BikeTypeInfo 获取车型信息
func (a *ebikeType) BikeTypeInfo(bikeTypeId int64) (info *entity.EbikeType, err error) {
	return a.iEbikeType.Find(bikeTypeId)
}

func (a *ebikeType) ParentList(ctx context.Context, in *model.ParentEbikeTypeRequest) ([]*model.ParentEbikeTypeList, error) {
	var (
		err  error
		list []*model.ParentEbikeTypeList
	)

	if list, err = a.iEbikeType.ParentList(in); err != nil {
		return nil, err
	}
	return list, err
}

func (a *ebikeType) Info(ctx context.Context, in *model.EbikeTypeBaseRequest) (*model.EbikeTypeInfo, error) {
	var (
		err        error
		info       *entity.EbikeType
		parentInfo *entity.EbikeType
		out        *model.EbikeTypeInfo
		parentName string
	)

	// 查询车型信息
	if info, err = a.iEbikeType.Find(in.ID); err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		return out, errors.EbikeModelNotExist.Error()
	} else if err != nil {
		return nil, err
	}

	// 查询父类型信息
	if info.ParentID != 0 {
		if parentInfo, err = a.iEbikeType.Find(info.ParentID); err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
			return out, errors.EbikeModelNotExist.Error()
		} else if err != nil {
			return nil, err
		}
		parentName = parentInfo.Name
	}

	// 转换输出
	out = &model.EbikeTypeInfo{
		ID:             info.ID,
		SocketType:     info.SocketType,
		Name:           info.Name,
		Status:         info.Status,
		ParentID:       info.ParentID,
		Price:          info.Price,
		ParentName:     parentName,
		Image:          info.Image,
		Code:           info.Code,
		Color:          info.Color,
		CreatedAt:      info.CreatedAt,
		UpdatedAt:      info.UpdatedAt,
		ImagePath:      info.ImagePath,
		Config:         info.Config,
		ConfigUpdateAt: info.ConfigUpdatedAt,
	}
	return out, err
}

func (a *ebikeType) ToggleStatus(ctx context.Context, in *model.EbikeTypeToggleStatusRequest) error {
	var (
		err         error
		updateModel *model.EbikeTypeUpdateRequest
	)
	updateModel = &model.EbikeTypeUpdateRequest{
		ID: in.ID,

		Status: in.Status,
	}

	// 更新
	err = a.Update(ctx, updateModel)
	if err != nil {
		return errors.EbikeModelUpdateFailed.Error()
	}
	return err
}

// GetBikeImage 获取车型图片
func (a *ebikeType) GetBikeImage(typeId int64, color string) string {
	return fmt.Sprintf("ebike_object/ebike_type/%v/%v", typeId, color)
}

// BatchBikeImage 批量获取车型图片
func (a *ebikeType) BatchBikeImage(bikeInfo []*model.GetBikeImage) (bikesImageMap map[int64]string) {
	bikesImageMap = make(map[int64]string)
	for i := 0; i < len(bikeInfo); i++ {
		bikesImageMap[bikeInfo[i].BikeId] = a.GetBikeImage(bikeInfo[i].TypeId, bikeInfo[i].Color)
	}

	return
}

func buildEbikeType(in *model.EbikeTypeCreateRequest) *entity.EbikeType {
	// todo: check the entity is required
	return &entity.EbikeType{

		SocketType: *in.SocketType,

		Name: in.Name,

		ParentID: in.ParentID,

		Price: *in.Price,

		Color: in.Color,

		Image: in.Image,

		Code: in.Code,

		Config: in.Config,

		CreatedAt: time.Now().Unix(),

		UpdatedAt: time.Now().Unix(),

		ConfigUpdatedAt: time.Now().Unix(),

		ImagePath: in.ImagePath,
	}
}
